package com.surprise.redis.util;

import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;

import redis.clients.jedis.Jedis;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.surprise.base.util.ListUtils;
import com.surprise.redis.LuaLoader;

/**
 * RedisUtils.java
 * @author nick
 * 2015年2月13日
 */
public class RedisUtils {
    /**
     * 判断sortedset key中是否存在member
     * 
     * @param jedis
     * @param key
     * @param member
     * @return true:exists, false:not exists
     */
    public static boolean zexists(Jedis jedis, String key, String member) {
        Double score = jedis.zscore(key, member);
        return score != null;
    }

    /**
     * 批量获取zset里面的score null if member not in zset
     * 
     * @param jedis
     * @param key
     * @param members
     * @return
     */
    public static Map<String, Double> zbatchscore(Jedis jedis, String key,
            List<String> members) {
        if (CollectionUtils.isEmpty(members)) {
            return null;
        }
        Map<String, Double> map = Maps.newHashMap();
        if (members.size() == 1) {
            Double score = jedis.zscore(key, members.get(0));
            map.put(members.get(0), score);
            return map;
        }

        List<String> scores = (List<String>) jedis.eval(
                LuaLoader.getLua("zbatch_get_score"), Lists.newArrayList(key),
                members);
        if (scores == null || scores.size() != members.size()) { // 异常流程，一个个取
            for (String member : members) {
                Double score = jedis.zscore(key, member);
                map.put(member, score);
            }
            return map;
        } else { // 正常流程
            for (int i = 0; i < members.size(); i++) {
                String score = scores.get(i);
                if (score == null) {
                    map.put(members.get(i), null);
                } else {
                    map.put(members.get(i), Double.valueOf(score));
                }
            }
            return map;
        }
    }

    public static Map<Long, Double> zbatchscoreL(Jedis jedis, String key,
            List<Long> members) {
        if (CollectionUtils.isEmpty(members)) {
            return null;
        }
        Map<Long, Double> map = Maps.newHashMap();
        if (members.size() == 1) {
            Double score = jedis.zscore(key, members.get(0) + "");
            if (score != null) {
            	map.put(members.get(0), score);
            }
            return map;
        }

        List<String> scores = (List<String>) jedis.eval(
                LuaLoader.getLua("zbatch_get_score"), Lists.newArrayList(key),
                ListUtils.convert(members, String.class));
        if (scores == null || scores.size() != members.size()) { // 异常流程，一个个取
            for (Long member : members) {
                Double score = jedis.zscore(key, member + "");
                map.put(member, score);
            }
            return map;
        } else { // 正常流程
            for (int i = 0; i < members.size(); i++) {
                String score = scores.get(i);
                if (score != null) {
                	map.put(members.get(i), Double.valueOf(score));
                }
            }
            return map;
        }
    }

    public static Map<Long, Integer> zbatchcountL(Jedis jedis, String key,
            List<Long> members) {
        if (CollectionUtils.isEmpty(members)) {
            return null;
        }
        Map<Long, Integer> map = Maps.newHashMap();
        if (members.size() == 1) {
            String member = members.get(0) + "";
            Double score = jedis.zscore(key, member);
            int count = score == null ? 0 : score.intValue();
            if (count < 0) {
                count = 0;
                // 如果存在负数，修正counter
                jedis.zadd(key, 0, member);
            }
            map.put(members.get(0), count);
            return map;
        }

        Map<String, Double> fixMap = Maps.newHashMap();
        List<String> scores = (List<String>) jedis.eval(
                LuaLoader.getLua("zbatch_get_score"), Lists.newArrayList(key),
                ListUtils.convert(members, String.class));
        if (scores == null || scores.size() != members.size()) { // 异常流程，一个个取
            for (Long mem : members) {
                String member = mem + "";
                Double score = jedis.zscore(key, member);
                int count = score == null ? 0 : score.intValue();
                if (count < 0) {
                    count = 0;
                    fixMap.put(member, 0d);
                }
                map.put(mem, count);
            }
        } else { // 正常流程
            for (int i = 0; i < members.size(); i++) {
                long member = members.get(i);
                String score = scores.get(i);
                if (score == null) {
                    map.put(member, 0);
                } else {
                    int count = score == null ? 0 : Integer.valueOf(score);
                    if (count < 0) {
                        count = 0;
                        fixMap.put(member + "", 0d);
                    }
                    map.put(member, count);
                }
            }
        }

        // 如果存在负数，修正counter
        if (fixMap.size() > 0) {
            jedis.zadd(key, fixMap);
        }

        return map;
    }

    /**
     * batch add counter
     * 
     * @param jedis
     * @param key
     * @param members
     * @param count
     */
    public static void batchAddCounter(Jedis jedis, String key,
            List<String> members, int count) {
        int last = members.size() + 1;
        String lua = String.format(LuaLoader.getLua("zbatch_add_counter"),
                last, count);
        jedis.eval(lua, Lists.newArrayList(key), members);
    }

    /**
     * 获取在zset中的members
     * 
     * @param jedis
     * @param key
     * @param members
     * @return
     */
    public static List<Long> zismemberL(Jedis jedis, String key,
            List<Long> members) {
        List<String> mems = ListUtils.convert(members, String.class);
        List<String> inMems = zismember(jedis, key, mems);
        return ListUtils.convert(inMems, Long.class);
    }

    /**
     * 获取不在zset中的members
     * 
     * @param jedis
     * @param key
     * @param members
     * @return
     */
    public static List<Long> zisnotmemberL(Jedis jedis, String key,
            List<Long> members) {
        List<String> mems = ListUtils.convert(members, String.class);
        List<String> notMems = zisnotmember(jedis, key, mems);
        return ListUtils.convert(notMems, Long.class);
    }

    /**
     * 获取在zset中的members
     * 
     * @param jedis
     * @param key
     * @param members
     * @return
     */
    public static List<String> zismember(Jedis jedis, String key,
            List<String> members) {
        Map<String, Double> scores = zbatchscore(jedis, key, members);
        List<String> ret = Lists.newArrayList();
        for (String member : members) {
            if (scores.get(member) != null) {
                ret.add(member);
            }
        }
        return ret;
    }

    /**
     * 获取不在zset中的members
     * 
     * @param jedis
     * @param key
     * @param members
     * @return
     */
    public static List<String> zisnotmember(Jedis jedis, String key,
            List<String> members) {
        Map<String, Double> scores = zbatchscore(jedis, key, members);
        List<String> ret = Lists.newArrayList();
        for (String member : members) {
            if (scores.get(member) == null) {
                ret.add(member);
            }
        }
        return ret;
    }
    
    public static List<String> lpopbatch(Jedis jedis, String key, int batch) {
        String lua = String.format(LuaLoader.getLua("lbatch_pop"), new Object[] {
                batch
        });
        List<String> messages = (List<String>) jedis.eval(lua, 1, new String[] {
                key
        });
        return messages;
    }
    
    public static long addCode(Jedis jedis, String totalKey, String countKey) {
    	String lua = String.format(LuaLoader.getLua("add_code"));
    	long ret = (Long)jedis.eval(lua, 2, totalKey, countKey);
    	return ret;
    }
}
